/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */

import { expect } from '@jest/globals';
import * as fse from 'fs-extra';
import * as path from 'path';
import { resolve } from 'path';

import { ModuleBuildProfile } from '../../../../src/options/build/module-build-profile';
import { initByStageEmptyApp, initByStageEmptyService, initExecuteCommand, runHvigor, } from '../../common/common';
import { ModuleBuildProfileModifier } from '../../common/modifier/module-build-profile-modifier';
import { ProjectBuildProfileModifier } from '../../common/modifier/project-build-profile-modifier';
import { Probes } from '../../common/probes';
import ModuleTargetBuildOpt = ModuleBuildProfile.ModuleTargetBuildOpt;

describe('test make pack info', () => {
  test.concurrent('test stage mode make pack info and incremental', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      const commands = initExecuteCommand({
        mode: 'module',
        product: 'default',
        module: 'entry',
        tasks: 'default@MakePackInfo',
        log: 'i'
      });

      // 第一次执行 expect Finish
      const result = runHvigor(projectRoot, commands);
      expect(result.stdout).toContain('Finished :entry:default@MakePackInfo...');
      expect(result.stdout).toContain('BUILD SUCCESSFUL');

      // 第二次执行 expect UpToDate
      const executeAgainResult = runHvigor(projectRoot, commands);
      expect(executeAgainResult.stdout).toContain('UP-TO-DATE :entry:default@MakePackInfo...');
      expect(executeAgainResult.stdout).toContain('BUILD SUCCESSFUL');

      // 删除输出
      const outputFile = path.resolve(projectRoot, 'entry/build/default/outputs/default/pack.info');
      fse.removeSync(outputFile);

      // 删除输出第一次执行 expect Finish
      const executeAgainResultAfterDelete = runHvigor(projectRoot, commands);
      expect(executeAgainResultAfterDelete.stdout).toContain('Finished :entry:default@MakePackInfo...');
      expect(executeAgainResultAfterDelete.stdout).toContain('BUILD SUCCESSFUL');
    });
  });

  test.concurrent('test stage mode make pack info change product bundle name', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      const commands = initExecuteCommand({
        mode: 'module',
        product: 'default',
        module: 'entry',
        tasks: 'default@MakePackInfo',
        log: 'i'
      });

      // 第一次执行 expect Finish
      const result = runHvigor(projectRoot, commands);
      expect(result.stdout).toContain('Finished :entry:default@MakePackInfo...');
      expect(result.stdout).toContain('BUILD SUCCESSFUL');

      // 第二次执行 expect UpToDate
      const executeAgainResult = runHvigor(projectRoot, commands);
      expect(executeAgainResult.stdout).toContain('UP-TO-DATE :entry:default@MakePackInfo...');
      expect(executeAgainResult.stdout).toContain('BUILD SUCCESSFUL');

      // 更新 build-profile.json5 中的 bundleName
      const projectBuildProfileModifier = new ProjectBuildProfileModifier(projectRoot);
      projectBuildProfileModifier.updateProduct({
        name: 'default',
        bundleName: 'com.example.myapplication.test'
      }).outputSync();

      // 更新bundleName后第一次执行 expect Finish
      const updateBundleNameResult = runHvigor(projectRoot, commands);
      expect(updateBundleNameResult.stdout).toContain('Finished :entry:default@MakePackInfo...');
      expect(updateBundleNameResult.stdout).toContain('BUILD SUCCESSFUL');

      // 更新bundleName后第二次执行 expect UpToDate
      const updateBundleNameResultRunAgain = runHvigor(projectRoot, commands);
      expect(updateBundleNameResultRunAgain.stdout).toContain('UP-TO-DATE :entry:default@MakePackInfo...');
      expect(updateBundleNameResultRunAgain.stdout).toContain('BUILD SUCCESSFUL');
    });
  });

  test.concurrent('test stage make pack info deviceType', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      const commands = initExecuteCommand({
        mode: 'module',
        product: 'default',
        module: 'entry',
        tasks: 'default@MakePackInfo',
      });

      const result = runHvigor(projectRoot, commands);
      expect(result.stdout.includes('BUILD SUCCESSFUL')).toBeTruthy();

      const probe = new Probes(projectRoot, resolve(projectRoot, 'entry'));
      const packInfo = fse.readJsonSync(path.resolve(probe.getModuleBuildOutputPath(), 'pack.info'));
      expect(packInfo.summary.modules[0].deviceType.length === 2).toBeTruthy();
      expect(packInfo.packages[0].deviceType.length === 2).toBeTruthy();
      expect(packInfo.packages[0].deviceType).toContain('default');
      expect(packInfo.packages[0].deviceType).toContain('tablet');

      const entryBuildProfile = new ModuleBuildProfileModifier(projectRoot, 'entry');
      const target: ModuleTargetBuildOpt = {
        name: 'default',
        config: {
          deviceType: ['tablet']
        }
      };
      entryBuildProfile.updateTarget(target).outputSync();

      const result2 = runHvigor(projectRoot, commands);
      expect(result2.stdout.includes('Finished :entry:default@MakePackInfo...')).toBeTruthy();
      expect(result2.stdout.includes('BUILD SUCCESSFUL')).toBeTruthy();

      const probe2 = new Probes(projectRoot, resolve(projectRoot, 'entry'));
      const packInfo2 = fse.readJsonSync(path.resolve(probe2.getModuleBuildOutputPath(), 'pack.info'));
      expect(packInfo2.summary.modules[0].deviceType.length === 1).toBeTruthy();
      expect(packInfo2.packages[0].deviceType.length === 1).toBeTruthy();
      expect(packInfo2.packages[0].deviceType).toContain('tablet');

      const result3 = runHvigor(projectRoot, commands);
      expect(result3.stdout.includes('UP-TO-DATE :entry:default@MakePackInfo...')).toBeTruthy();
      expect(result3.stdout.includes('BUILD SUCCESSFUL')).toBeTruthy();
    });
  });

  test.concurrent('test stage app: feature includes entry info', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      const commands = initExecuteCommand({
        mode: 'module',
        product: 'default',
        module: 'feature',
        tasks: 'default@MakePackInfo',
      });
      const result = runHvigor(projectRoot, commands);
      expect(result.stdout.includes('BUILD SUCCESSFUL')).toBeTruthy();

      const probe = new Probes(projectRoot, resolve(projectRoot, 'feature'));
      const packinfo = fse.readJsonSync(path.resolve(probe.getModuleBuildOutputPath(), 'entry', 'pack.info'));
      expect(packinfo.summary.modules.length === 2).toBeTruthy();
    });
  });

  test.concurrent('test stage service: feature includes entry info', async () => {
    await initByStageEmptyService(async (projectRoot) => {
      const commands = initExecuteCommand({
        mode: 'module',
        product: 'default',
        module: 'feature',
        tasks: 'default@MakePackInfo',
      });

      const result = runHvigor(projectRoot, commands);
      expect(result.stdout.includes('BUILD SUCCESSFUL')).toBeTruthy();

      const probe = new Probes(projectRoot, resolve(projectRoot, 'feature'));
      const packinfo = fse.readJsonSync(path.resolve(probe.getModuleBuildOutputPath(), 'entry', 'pack.info'));
      expect(packinfo.summary.modules.length === 2).toBeTruthy();
    });
  });

  test.concurrent('test stage app: feature/entry unmatched target', async () => {
    await initByStageEmptyApp(async (projectRoot) => {
      const commands = initExecuteCommand({
        mode: 'module',
        product: 'default',
        module: 'feature',
        tasks: 'default1@MakePackInfo',
      });
      const featureBuildProfile = new ModuleBuildProfileModifier(projectRoot, 'feature');
      const target: ModuleTargetBuildOpt = {
        name: 'default1',
        config: {
          deviceType: ['tablet']
        }
      };
      featureBuildProfile.updateTarget(target).outputSync();
      const result = runHvigor(projectRoot, commands);
      expect(result.stdout.includes('BUILD SUCCESSFUL')).toBeTruthy();

      const probe = new Probes(projectRoot, resolve(projectRoot, 'feature'), 'default1');
      const packinfo = fse.readJsonSync(path.resolve(probe.getModuleBuildOutputPath(), 'entry', 'pack.info'));
      expect(packinfo.summary.modules.length === 2).toBeTruthy();
      expect(packinfo.summary.modules[1].deviceType.length === 1).toBeTruthy();
    });
  });

  test.concurrent('test stage service: feature/entry unmatched target', async () => {
    await initByStageEmptyService(async (projectRoot) => {
      const commands = initExecuteCommand({
        mode: 'module',
        product: 'default',
        module: 'feature',
        tasks: 'default1@MakePackInfo',
      });
      const featureBuildProfile = new ModuleBuildProfileModifier(projectRoot, 'feature');
      const target: ModuleTargetBuildOpt = {
        name: 'default1',
        config: {
          deviceType: ['tablet']
        }
      };
      featureBuildProfile.updateTarget(target).outputSync();
      new ModuleBuildProfileModifier(projectRoot, 'feature').updateTargetRuntimeOS('default1', 'HarmonyOS');
      const result = runHvigor(projectRoot, commands);
      expect(result.stdout.includes('BUILD SUCCESSFUL')).toBeTruthy();

      const probe = new Probes(projectRoot, resolve(projectRoot, 'feature'), 'default1');
      const packinfo = fse.readJsonSync(path.resolve(probe.getModuleBuildOutputPath(), 'entry', 'pack.info'));
      expect(packinfo.summary.modules.length === 2).toBeTruthy();
      expect(packinfo.summary.modules[1].deviceType.length === 1).toBeTruthy();
    });
  });
});
